package com.threeox.commonlibrary.ui.view.pullrefresh.base;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

import com.threeox.commonlibrary.R;
import com.threeox.commonlibrary.entity.engine.model.listmodel.ListModelMsg;
import com.threeox.commonlibrary.ui.view.OverallInitView;
import com.threeox.commonlibrary.ui.view.inter.pullrefresh.IHeaderFooter;
import com.threeox.commonlibrary.ui.view.inter.pullrefresh.IPullToRefLayout;
import com.threeox.commonlibrary.ui.view.inter.pullrefresh.IPullable;
import com.threeox.commonlibrary.ui.view.inter.pullrefresh.OnRefreshListener;
import com.threeox.commonlibrary.ui.view.pullrefresh.PullToRefreshExpandListView;
import com.threeox.commonlibrary.ui.view.pullrefresh.PullToRefreshGridView;
import com.threeox.commonlibrary.ui.view.pullrefresh.PullToRefreshListView;
import com.threeox.commonlibrary.ui.view.pullrefresh.PullToRefreshScrollView;
import com.threeox.commonlibrary.util.CommonConstant.HeaderFooter;
import com.threeox.commonlibrary.util.CommonUtils;
import com.threeox.utillibrary.util.EmptyUtils;
import com.threeox.utillibrary.util.res.LayoutParamsUtils;
import com.threeox.utillibrary.util.thread.ThreadUtil;

import java.util.Timer;
import java.util.TimerTask;

/**
 * 
 * @ClassName: PullToRefreshLayout
 * 
 * @Description: TODO(上拉和下拉的View)
 * 
 * @author 赵屈犇
 * 
 * @date 2016-9-13 上午11:24:51
 *
 * @version 1.0
 */
@SuppressLint("NewApi")
public class PullToRefreshLayout extends RelativeLayout implements IPullToRefLayout {

	private Context mContext;
	private IHeaderFooter mHeadView, mFooterView;
	// 实现了IPullable 接口的拉动View
	private View mPullView;
	private int mHeaderViewHeight;
	private int mFooterViewHeight;

    private ListModelMsg mListModelMsg;

	private final String TAG = PullToRefreshLayout.class.getName();
	// 当前状态
	public int state = IPullToRefLayout.INIT;

	// 按下Y坐标，上一个事件点Y坐标
	private float downY, lastY;

	private MyTimer timer;
	// 回滚速度
	public float MOVE_SPEED = 8.0f;
	// 第一次执行布局
	private boolean isLayout = false;
	// 在刷新过程中滑动操作
	private boolean isTouch = false;
	// 手指滑动距离与下拉头的滑动距离比，中间会随正切函数变化
	private float radio = 2.0f;
	// 过滤多点触碰
	private int mEvents;
	// 这两个变量用来控制pull的方向，如果不加控制，当情况满足可上拉又可下拉时没法下拉
	private boolean canPullDown = true;
	private boolean canPullUp = true;

	// 释放刷新的距离
	private float refreshDist = 200.0f;
	// 释放加载的距离
	private float loadmoreDist = 200.0f;

	// 下拉的距离。注意：pullDownY和pullUpY不可能同时不为0
	public float pullDownY = 0.0f;
	// 上拉的距离
	private float pullUpY = 0.0f;

	private OnRefreshListener onRefreshListener;

	// 底部和顶部显示规则
	private String mHeaderFooterType;
	// 默认可以下拉
	private boolean isPull = true;

	private int mViewType;
	private int listview = 0, gridview = 1, expanlistview = 2, scrollview = 3;

	private OverallInitView mOverallInitView;
    private LayoutParamsUtils mLayoutParamsUtils;

	/**
	 * 执行自动回滚的handler
	 */
	Handler updateHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			// 回弹速度随下拉距离moveDeltaY增大而增大
			MOVE_SPEED = (float) (8 + 5 * Math.tan(Math.PI / 2
					/ getMeasuredHeight() * (pullDownY + Math.abs(pullUpY))));
			if (!isTouch) {
				// 正在刷新，且没有往上推的话则悬停，显示"正在刷新..."
				if (state == REFRESHING && pullDownY <= refreshDist) {
					pullDownY = refreshDist;
					timer.cancel();
				} else if (state == LOADING && -pullUpY <= loadmoreDist) {
					pullUpY = -loadmoreDist;
					timer.cancel();
				}
			}
			if (pullDownY > 0)
				pullDownY -= MOVE_SPEED;
			else if (pullUpY < 0)
				pullUpY += MOVE_SPEED;
			if (pullDownY < 0) {
				// 已完成回弹
				pullDownY = 0;
				// pullView.clearAnimation();
				// 隐藏下拉头时有可能还在刷新，只有当前状态不是正在刷新时才改变状态
				if (state != REFRESHING && state != LOADING)
					changeState(INIT);
				timer.cancel();
				requestLayout();
			}
			if (pullUpY > 0) {
				// 已完成回弹
				pullUpY = 0;
				// pullUpView.clearAnimation();
				// 隐藏上拉头时有可能还在刷新，只有当前状态不是正在刷新时才改变状态
				if (state != REFRESHING && state != LOADING)
					changeState(INIT);
				timer.cancel();
				requestLayout();
			}
			Log.d("handle", "handle");
			// 刷新布局,会自动调用onLayout
			requestLayout();
			// 没有拖拉或者回弹完成
			if (pullDownY + Math.abs(pullUpY) == 0)
				timer.cancel();
		}

	};

	public PullToRefreshLayout(Context context) {
		this(context, null);
	}

	public PullToRefreshLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PullToRefreshLayout);
		if (ta != null) {
			mViewType = ta.getInteger(R.styleable.PullToRefreshLayout_pf_view, 0);
			if (mViewType == listview) {
				init(context, new PullToRefreshLayout(context));
			} else if (mViewType == gridview) {
				init(context, new PullToRefreshGridView(context));
			} else if (mViewType == expanlistview) {
				init(context, new PullToRefreshExpandListView(context));
			} else if (mViewType == scrollview) {
                init(context, new PullToRefreshScrollView(context));
            }
		} else {
			init(context, null);
		}
	}

	public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyle, View cententView) {
		super(context, attrs, defStyle);
		init(context, cententView);
	}

	/**
	 * 初始化cententView
	 * 
	 * @param context
	 * @param cententView
	 */
	private void init(Context context, View cententView) {
		this.mContext = context;
		this.mHeaderFooterType = HeaderFooter.ShowAll;
		timer = new MyTimer(updateHandler);
		cententView = cententView == null ? new PullToRefreshListView(mContext) : cententView;
        mLayoutParamsUtils = LayoutParamsUtils.newInstance(mContext);
		mOverallInitView = OverallInitView.newInstance(mContext);
		initView(cententView);
	}

	/**
	 * 初始化View
	 */
	private void initView(View cententView) {
		initHeadView();
		// 中间的View 最主要的
		mPullView = cententView;
		mPullView.setLayoutParams(mLayoutParamsUtils.getRelativeLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		mPullView.setId(R.id.id_content_view);
		this.addView(mPullView);
		initFooterView();
	}

	/**
	 * 初始化HeadView
	 */
	private void initHeadView() {
		mHeadView = mOverallInitView.initPullToRefreshHeaderView();
		mHeadView.setLayoutParams(mLayoutParamsUtils.getRelativeLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
		mHeadView.measure(0, 0); // 系统会帮我们测量出headerView的高度
		mHeaderViewHeight = mHeadView.getMeasuredHeight();
		refreshDist = mHeaderViewHeight;
		this.addView((View) mHeadView);
	}

	/**
	 * 初始化底部View
	 */
	private void initFooterView() {
		mFooterView = mOverallInitView.initPullToRefreshFooterView();
		mFooterView.setLayoutParams(mLayoutParamsUtils.getRelativeLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
		mFooterView.measure(0, 0);
		mFooterViewHeight = mFooterView.getMeasuredHeight();
		loadmoreDist = mFooterViewHeight;
		this.addView((View) mFooterView);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		// LogUtils.e(TAG, TAG + ":dispatchTouchEvent");
		if (!isPull) {
			// LogUtils.e(TAG, TAG + "不能滑动了,子类把我禁用了!");
			return super.dispatchTouchEvent(ev);
		}
		if (downY == -1) {
			downY = ev.getY();
		}
		switch (ev.getActionMasked()) {
		case MotionEvent.ACTION_DOWN:
			downY = ev.getY();
			lastY = downY;
			timer.cancel();
			mEvents = 0;
			releasePull();
			break;
		case MotionEvent.ACTION_POINTER_DOWN:
		case MotionEvent.ACTION_POINTER_UP:
			// 过滤多点触碰
			mEvents = -1;
			break;
		case MotionEvent.ACTION_MOVE:
			if (mEvents == 0) {
				if (CommonUtils.isNaN(pullDownY)) {
					pullDownY = 0.0f;
				}
				if (pullDownY > 0
						|| (((IPullable) mPullView).isPullDown() && canPullDown && state != LOADING)) {
					// 可以下拉，正在加载时不能下拉
					// 对实际滑动距离做缩小，造成用力拉的感觉
					pullDownY = pullDownY + (ev.getY() - lastY) / radio;
					if (pullDownY < 0) {
						pullDownY = 0;
						canPullDown = false;
						canPullUp = true;
					}
					if (pullDownY > getMeasuredHeight())
						pullDownY = getMeasuredHeight();
					if (state == REFRESHING) {
						// 正在刷新的时候触摸移动
						isTouch = true;
						// BaseUtils.showToast("正在刷新中...");
					}
				} else if (pullUpY < 0
						|| (((IPullable) mPullView).isPullUp() && canPullUp && state != REFRESHING)) {
					// 可以上拉，正在刷新时不能上拉
					pullUpY = pullUpY + (ev.getY() - lastY) / radio;
					if (pullUpY > 0) {
						pullUpY = 0;
						canPullDown = true;
						canPullUp = false;
					}
					if (pullUpY < -getMeasuredHeight())
						pullUpY = -getMeasuredHeight();
					if (state == LOADING) {
						// 正在加载的时候触摸移动
						isTouch = true;
						// BaseUtils.showToast("正在加载中...");
					}
				} else
					releasePull();
			} else
				mEvents = 0;
			lastY = ev.getY();
			// 根据下拉距离改变比例
			radio = (float) (2 + 2 * Math.tan(Math.PI / 2 / getMeasuredHeight()
					* (pullDownY + Math.abs(pullUpY))));
			if (pullDownY > 0 || pullUpY < 0)
				requestLayout();
			if (pullDownY > 0) {
				if (pullDownY <= refreshDist
						&& (state == RELEASE_TO_REFRESH || state == DONE)) {
					// 如果下拉距离没达到刷新的距离且当前状态是释放刷新，改变状态为下拉刷新
					changeState(INIT);
				}
				if (pullDownY >= refreshDist && state == INIT) {
					// 如果下拉距离达到刷新的距离且当前状态是初始状态刷新，改变状态为释放刷新
					changeState(RELEASE_TO_REFRESH);
				}
			} else if (pullUpY < 0) {
				// 下面是判断上拉加载的，同上，注意pullUpY是负值
				if (-pullUpY <= loadmoreDist
						&& (state == RELEASE_TO_LOAD || state == DONE)) {
					changeState(INIT);
				}
				// 上拉操作
				if (-pullUpY >= loadmoreDist && state == INIT) {
					changeState(RELEASE_TO_LOAD);
				}

			}
			// 因为刷新和加载操作不能同时进行，所以pullDownY和pullUpY不会同时不为0，因此这里用(pullDownY +
			// Math.abs(pullUpY))就可以不对当前状态作区分了
			if ((pullDownY + Math.abs(pullUpY)) > 8) {
				// 防止下拉过程中误触发长按事件和点击事件
				ev.setAction(MotionEvent.ACTION_CANCEL);
			}
			break;
		case MotionEvent.ACTION_UP:
			if (pullDownY > refreshDist || -pullUpY > loadmoreDist)
			// 正在刷新时往下拉（正在加载时往上拉），释放后下拉头（上拉头）不隐藏
			{
				isTouch = false;
			}
			if (state == RELEASE_TO_REFRESH) {
				if (!HeaderFooter.HideAll.equals(mHeaderFooterType) && !HeaderFooter.HideHeader.equals(mHeaderFooterType)) {
					changeState(REFRESHING);
					// 刷新操作
					if (onRefreshListener != null)
						onRefreshListener.onDownPullRefresh();
				} else {
					changeState(DONE);
				}
			} else if (state == RELEASE_TO_LOAD) {
				if (!HeaderFooter.HideAll.equals(mHeaderFooterType)  && !HeaderFooter.HideFooter.equals(mHeaderFooterType)) {
					changeState(LOADING);
					// 加载操作
					if (onRefreshListener != null)
						onRefreshListener.onLoadingMore();
				} else {
					changeState(DONE);
				}
			}
			hide();
		default:
			break;
		}
		// 事件分发交给父类
		super.dispatchTouchEvent(ev);
		return true;
	}

	public void changeState(int to) {
		// LogUtils.e("正在操作" + to);
		state = to;
		switch (state) {
		case INIT:
			if (mHeadView != null){
                mHeadView.init((mListModelMsg != null && EmptyUtils.isNotEmpty(mListModelMsg.getRefreshText()))
                        ? mListModelMsg.getRefreshText() : null);
			}
			if (mFooterView != null){
                mFooterView.init((mListModelMsg != null && EmptyUtils.isNotEmpty(mListModelMsg.getLoadText()))
                        ? mListModelMsg.getLoadText() : null);
			}
			break;
		case RELEASE_TO_REFRESH:
			if (mHeadView != null){
				mHeadView.release((mListModelMsg != null && EmptyUtils.isNotEmpty(mListModelMsg.getReleaseRefreshText()))
                        ? mListModelMsg.getReleaseRefreshText() : null);
			}
			break;
		case REFRESHING:
			if (mHeadView != null){
				mHeadView.loading((mListModelMsg != null && EmptyUtils.isNotEmpty(mListModelMsg.getRefreshingText()))
                        ? mListModelMsg.getRefreshingText() : null);
			}
			break;
		case RELEASE_TO_LOAD:
			if (mFooterView != null){
				mFooterView.release((mListModelMsg != null && EmptyUtils.isNotEmpty(mListModelMsg.getReleaseLoadText()))
                        ? mListModelMsg.getReleaseLoadText() : null);
			}
			break;
		case LOADING:
			if (mFooterView != null){
				mFooterView.loading((mListModelMsg != null && EmptyUtils.isNotEmpty(mListModelMsg.getLoadingText()))
                        ? mListModelMsg.getLoadingText() : null);
			}
			break;
		case DONE:
			// 刷新或加载完毕，啥都不做
			break;
		}
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        // 改变子控件的布局，这里直接用(pullDownY + pullUpY)作为偏移量，这样就可以不对当前状态作区分
        mHeadView.layout(0, (int) (pullDownY + pullUpY) - mHeadView.getMeasuredHeight(),
                mHeadView.getMeasuredWidth(), (int) (pullDownY + pullUpY));
        mPullView.layout(0, (int) (pullDownY + pullUpY),
                mPullView.getMeasuredWidth(), (int) (pullDownY + pullUpY)
                        + mPullView.getMeasuredHeight());
        mFooterView.layout(0,
                (int) (pullDownY + pullUpY) + mPullView.getMeasuredHeight(),
                mFooterView.getMeasuredWidth(),
                (int) (pullDownY + pullUpY) + mPullView.getMeasuredHeight()
                        + mFooterView.getMeasuredHeight());
	}

	private void hide() {
		timer.schedule(5);
	}

	/**
	 * 不限制上拉或下拉
	 */
	private void releasePull() {
		canPullDown = true;
		canPullUp = true;
	}

	class MyTimer {
		private Handler handler;
		private Timer timer;
		private MyTask mTask;

		public MyTimer(Handler handler) {
			this.handler = handler;
			timer = new Timer();
		}

		public void schedule(long period) {
			if (mTask != null) {
				mTask.cancel();
				mTask = null;
			}
			mTask = new MyTask(handler);
			timer.schedule(mTask, 0, period);
		}

		public void cancel() {
			if (mTask != null) {
				mTask.cancel();
				mTask = null;
			}
		}

		class MyTask extends TimerTask {
			private Handler handler;

			public MyTask(Handler handler) {
				this.handler = handler;
			}

			@Override
			public void run() {
				handler.obtainMessage().sendToTarget();
			}

		}
	}

	public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
		this.onRefreshListener = onRefreshListener;
	}

	/**
	 * 得到最主要的那个View
	 * 
	 * @return
	 */
	@Override
	public <T extends View> T getMainView() {
		return (T) mPullView;
	}

    @Override
    public void setListModelMsg(ListModelMsg listModelMsg) {
        this.mListModelMsg = listModelMsg;
    }

    /**
	 * 完成刷新操作，显示刷新结果。注意：刷新完成后一定要调用这个方法
	 * @param refreshResult
	 *					IPullToRefLayout.SUCCEED代表成功，IPullToRefLayout.FAIL代表失败
	 * @param msg
     */
	@Override
	public void refreshFinish(int refreshResult, String msg) {
		if (state != REFRESHING) {// 正在刷新状态中
			// LogUtils.d(TAG, "没有正在刷新操作...");
			return;
		}
		switch (refreshResult) {
		case SUCCEED:
			if (mHeadView != null){
				mHeadView.loadSucceed((mListModelMsg != null && EmptyUtils.isNotEmpty(mListModelMsg.getRefreshSucceedText()))
                        ? mListModelMsg.getRefreshSucceedText() : msg);
			}
			break;
		case FAIL:
		default:
			if (mHeadView != null){
				mHeadView.loadFailed((mListModelMsg != null && EmptyUtils.isNotEmpty(mListModelMsg.getRefreshFailText()))
                        ? mListModelMsg.getRefreshFailText() : msg);
			}
			break;
		}
		if (pullDownY > 0) {
			// 刷新结果停留1秒
			new Handler() {
				@Override
				public void handleMessage(Message msg) {
					changeState(DONE);
					hide();
				}
			}.sendEmptyMessageDelayed(0, 1000);
		} else {
			changeState(DONE);
			hide();
		}
	}

	/**
	 * 加载完毕，显示加载结果。注意：加载完成后一定要调用这个方法
	 * @param refreshResult
	 * 					IPullToRefLayout.SUCCEED代表成功，IPullToRefLayout.FAIL代表失败
	 * @param msg
     */
	@Override
	public void loadmoreFinish(int refreshResult, String msg) {
		if (state != LOADING) {
			// LogUtils.d(TAG, "没有正在加载操作...");
			return;
		}
		switch (refreshResult) {
		case SUCCEED:
			if (mFooterView != null){
                mFooterView.loadSucceed((mListModelMsg != null && EmptyUtils.isNotEmpty(mListModelMsg.getLoadSucceedText()))
                        ? mListModelMsg.getLoadSucceedText() : msg);
            }
			break;
		case FAIL:
		default:
			if (mFooterView != null){
				mFooterView.loadFailed((mListModelMsg != null && EmptyUtils.isNotEmpty(mListModelMsg.getLoadFailText()))
                        ? mListModelMsg.getLoadFailText() : msg);
			}
			break;
		}
		if (pullUpY < 0) {
			// 刷新结果停留1秒
			new Handler() {
				@Override
				public void handleMessage(Message msg) {
					changeState(DONE);
					hide();
				}
			}.sendEmptyMessageDelayed(0, 1000);
		} else {
			changeState(DONE);
			hide();
		}
	}

	/**
	 * 显示头布局
	 */
	public void showHeader() {
		ThreadUtil.runInThread(new Runnable() {

			@Override
			public void run() {
				while (pullDownY < 4 / 3 * refreshDist) {
					pullDownY += MOVE_SPEED;
					changeState();
				}
			}
		});
	}

	private void changeState() {
		ThreadUtil.runUIThread(new Runnable() {

			@Override
			public void run() {
				// if (pullDownY > refreshDist)
				changeState(REFRESHING);
				requestLayout();
			}
		});
	}

	/**
	 * 自动加载
	 */
	public void autoLoad() {
		pullUpY = -loadmoreDist;
		requestLayout();
		changeState(LOADING);
		// 加载操作
		// if (mListener != null)
		// mListener.onLoadMore(this);
	}

	/**
	 * 判断是否可以下拉
	 * 
	 * @return
	 */
	public boolean isPullDown() {
		return ((IPullable) getMainView()).isPullDown();
	}

	/**
	 * 设置上拉和下拉的状态
	 * 
	 * @param headerFooterType
	 */
	@Override
	public void setHeaderFooterType(String headerFooterType){
		this.mHeaderFooterType = headerFooterType;
		if (HeaderFooter.HideAll.equals(mHeaderFooterType)) {
			mHeadView.setVisibility(View.GONE);
			mFooterView.setVisibility(View.GONE);
		} else if (HeaderFooter.HideFooter.equals(mHeaderFooterType)) {
			mFooterView.setVisibility(View.GONE);
		} else if (HeaderFooter.HideHeader.equals(mHeaderFooterType)) {
			mHeadView.setVisibility(View.GONE);
		} else {
			mHeadView.setVisibility(View.VISIBLE);
			mFooterView.setVisibility(View.VISIBLE);
		}
	}

	public void setPull(boolean isPull) {
		this.isPull = isPull;
	}

}
